// Copyright (c) 2024 CHANGLEI. All rights reserved.

import 'package:charts_grasp/src/chart/common/data_label.dart';
import 'package:charts_grasp/src/chart/utils/enum.dart';
import 'package:charts_grasp/src/circular_chart/base/circular_base.dart';
import 'package:charts_grasp/src/circular_chart/base/circular_state_properties.dart';
import 'package:charts_grasp/src/circular_chart/renderer/chart_point.dart';
import 'package:charts_grasp/src/circular_chart/renderer/circular_series.dart';
import 'package:charts_grasp/src/circular_chart/renderer/radial_bar_series.dart';
import 'package:charts_grasp/src/circular_chart/renderer/renderer_extension.dart';
import 'package:charts_grasp/src/common/utils/helper.dart';
import 'package:charts_grasp/src/core/theme.dart';
import 'package:flutter/material.dart';

class Region {
  Region(this.start, this.end, this.startAngle, this.endAngle, this.seriesIndex, this.pointIndex, this.center,
      this.innerRadius, this.outerRadius,);

  int seriesIndex;

  int pointIndex;

  num startAngle;

  num start;

  num end;

  num endAngle;

  Offset? center;

  num? innerRadius;

  num outerRadius;
}

class StyleOptions {
  StyleOptions({this.fill, this.strokeWidth, this.strokeColor, this.opacity});

  Color? fill;

  Color? strokeColor;

  double? opacity;

  num? strokeWidth;
}

class ChartInteraction {
  ChartInteraction(this.seriesIndex, this.pointIndex, this.series, this.point, [this.region]);

  int? seriesIndex;

  int? pointIndex;

  dynamic series;

  dynamic point;

  Region? region;
}

Color getCircularDataLabelColor(ChartPoint<dynamic> currentPoint, CircularSeriesRendererExtension seriesRenderer,
    CircularStateProperties stateProperties,) {
  Color color;
  final DataLabelSettings dataLabel = seriesRenderer.series.dataLabelSettings;
  final DataLabelSettingsRenderer dataLabelSettingsRenderer = seriesRenderer.dataLabelSettingsRenderer;
  final String seriesType = seriesRenderer.seriesType == 'pie'
      ? 'Pie'
      : seriesRenderer.seriesType == 'doughnut'
          ? 'Doughnut'
          : seriesRenderer.seriesType == 'radialbar'
              ? 'RadialBar'
              : 'Default';
  switch (seriesType) {
    case 'Pie':
    case 'Doughnut':
      color = (currentPoint.renderPosition == ChartDataLabelPosition.inside && !currentPoint.saturationRegionOutside)
          ? getInnerColor(
              dataLabelSettingsRenderer.color, currentPoint.fill, stateProperties.renderingDetails.chartTheme,)
          : getOuterColor(
              dataLabelSettingsRenderer.color,
              dataLabel.useSeriesColor
                  ? currentPoint.fill
                  : (stateProperties.chart.backgroundColor ??
                      stateProperties.renderingDetails.chartTheme.plotAreaBackgroundColor),
              stateProperties.renderingDetails.chartTheme,);
      break;
    case 'RadialBar':
      final RadialBarSeries<dynamic, dynamic> radialBar = seriesRenderer.series as RadialBarSeries<dynamic, dynamic>;
      color = radialBar.trackColor;
      break;
    default:
      color = Colors.white;
      break;
  }
  return getSaturationColor(color);
}

Color getInnerColor(Color? dataLabelColor, Color? pointColor, CgChartThemeData theme) =>
    dataLabelColor ??
    (pointColor ?? (theme.brightness == Brightness.light ? const Color.fromRGBO(255, 255, 255, 1) : Colors.black));

Color getOuterColor(Color? dataLabelColor, Color backgroundColor, CgChartThemeData theme) =>
    dataLabelColor ??
    (backgroundColor != Colors.transparent
        ? backgroundColor
            : theme.brightness == Brightness.light
                ? const Color.fromRGBO(255, 255, 255, 1)
            : Colors.black);

bool checkIsAnyPointSelect(
    CircularSeriesRendererExtension seriesRenderer, ChartPoint<dynamic>? point, CgCircularChart chart,) {
  bool isAnyPointSelected = false;
  final CircularSeries<dynamic, dynamic> series = seriesRenderer.series;
  if (series.initialSelectedDataIndexes.isNotEmpty) {
    int data;
    for (int i = 0; i < series.initialSelectedDataIndexes.length; i++) {
      data = series.initialSelectedDataIndexes[i];
      for (int j = 0; j < seriesRenderer.renderPoints!.length; j++) {
        if (j == data) {
          isAnyPointSelected = true;
          break;
        }
      }
    }
  }
  return isAnyPointSelected;
}

abstract class CircularChartSegment {
  Color? getPointColor(CircularSeriesRendererExtension seriesRenderer, ChartPoint<dynamic> point, int pointIndex,
      int seriesIndex, Color color, double opacity,);

  double getOpacity(CircularSeriesRendererExtension seriesRenderer, ChartPoint<dynamic>? point, int pointIndex,
      int seriesIndex, double opacity,);

  Color getPointStrokeColor(CircularSeriesRendererExtension seriesRenderer, ChartPoint<dynamic>? point, int pointIndex,
      int seriesIndex, Color strokeColor,);

  num getPointStrokeWidth(CircularSeriesRendererExtension seriesRenderer, ChartPoint<dynamic>? point, int pointIndex,
      int seriesIndex, num strokeWidth,);
}

abstract class LabelSegment {
  String getLabelContent(CircularSeriesRendererExtension seriesRenderer, ChartPoint<dynamic> point, int pointIndex,
      int seriesIndex, String content,);

  TextStyle getDataLabelStyle(CircularSeriesRendererExtension seriesRenderer, ChartPoint<dynamic> point, int pointIndex,
      int seriesIndex, TextStyle style, CgCircularChartState chartState,);

  Color? getDataLabelColor(CircularSeriesRendererExtension seriesRenderer, ChartPoint<dynamic> point, int pointIndex,
      int seriesIndex, Color? color,);

  Color getDataLabelStrokeColor(CircularSeriesRendererExtension seriesRenderer, ChartPoint<dynamic> point,
      int pointIndex, int seriesIndex, Color strokeColor,);

  double getDataLabelStrokeWidth(CircularSeriesRendererExtension seriesRenderer, ChartPoint<dynamic> point,
      int pointIndex, int seriesIndex, double strokeWidth,);
}

class ChartSeriesRender with CircularChartSegment, LabelSegment {
  ChartSeriesRender();

  @override
  Color? getPointColor(CircularSeriesRendererExtension seriesRenderer, ChartPoint<dynamic> point, int pointIndex,
          int seriesIndex, Color color, double opacity,) =>
      color.withOpacity(opacity);

  @override
  Color getPointStrokeColor(CircularSeriesRendererExtension seriesRenderer, ChartPoint<dynamic>? point, int pointIndex,
          int seriesIndex, Color strokeColor,) =>
      strokeColor;

  @override
  num getPointStrokeWidth(CircularSeriesRendererExtension seriesRenderer, ChartPoint<dynamic>? point, int pointIndex,
          int seriesIndex, num strokeWidth,) =>
      strokeWidth;

  @override
  String getLabelContent(CircularSeriesRendererExtension seriesRenderer, ChartPoint<dynamic> point, int pointIndex,
          int seriesIndex, String content,) =>
      content;

  @override
  TextStyle getDataLabelStyle(CircularSeriesRendererExtension seriesRenderer, ChartPoint<dynamic> point, int pointIndex,
      int seriesIndex, TextStyle style, CgCircularChartState chartState,) {
    final DataLabelSettings dataLabel = seriesRenderer.series.dataLabelSettings;
    final TextStyle textStyle = style.copyWith(
        color: _isCustomTextColor(
                dataLabel.textStyle, seriesRenderer.stateProperties.renderingDetails.chartTheme.dataLabelTextStyle,)
            ? dataLabel.textStyle?.color
            : getCircularDataLabelColor(point, seriesRenderer, seriesRenderer.stateProperties),);
    return textStyle;
  }

  bool _isCustomTextColor(TextStyle? textStyle, TextStyle? themeStyle) {
    return textStyle?.color != null || themeStyle?.color != null;
  }

  @override
  Color? getDataLabelColor(CircularSeriesRendererExtension seriesRenderer, ChartPoint<dynamic> point, int pointIndex,
          int seriesIndex, Color? color,) =>
      color;

  @override
  Color getDataLabelStrokeColor(CircularSeriesRendererExtension seriesRenderer, ChartPoint<dynamic> point,
          int pointIndex, int seriesIndex, Color? strokeColor,) =>
      strokeColor ?? point.fill;

  @override
  double getDataLabelStrokeWidth(CircularSeriesRendererExtension seriesRenderer, ChartPoint<dynamic> point,
          int pointIndex, int seriesIndex, double strokeWidth,) =>
      strokeWidth;

  @override
  double getOpacity(CircularSeriesRendererExtension seriesRenderer, ChartPoint<dynamic>? point, int pointIndex,
          int seriesIndex, double opacity,) =>
      opacity;
}
